package com.ruoyi.backend.service.Impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.backend.config.InversionDelayRabbitmqConfig;
import com.ruoyi.backend.controller.EcologicalController;
import com.ruoyi.backend.dto.EcologicalDataDTO;
import com.ruoyi.backend.pojo.EcologicalData;
import com.ruoyi.backend.util.MinioUtil;
import com.ruoyi.backend.vo.EcologicalDataVO;
import com.ruoyi.common.annotation.DataSource;
import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.exception.backendEnum.EcologicalDataException;
import com.ruoyi.integration.dto.InversionResultDTO;
import com.ruoyi.backend.enumClass.sseVoEnum;
import com.ruoyi.backend.mapper.*;
import com.ruoyi.backend.pojo.InversionResultData;
import com.ruoyi.backend.propertyConfig.GeoserverConfig;
import com.ruoyi.backend.service.EcologicalService;
import com.ruoyi.integration.service.InverseService;
import com.ruoyi.integration.vo.DataSourcesVO;
import com.ruoyi.backend.vo.InversionResultVO;
import com.ruoyi.backend.vo.InversionSseVO;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.sql.Date;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service("BackendEcologicalServiceImpl")
public class EcologicalServiceImpl implements EcologicalService {

    @Autowired
    private EcologicalMapper ecologicalMapper;


    @Autowired
    private InverseService inverseService;

    @Autowired
    private SatelliteDataMapper satelliteDataMapper;

    @Autowired
    private InversionResultDataMapper inversionResultDataMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Value("${minio-bucket.ecologicalfile}")
    private String storageLocation;

    private final static Logger logger = LoggerFactory.getLogger(EcologicalController.class);

    @Autowired
    SatelliteMapper satelliteMapper;

    @Autowired
    UavMapper uavMapper;

    @Autowired
    GeoserverConfig geoserverConfig;

    @Autowired
    MinioUtil minioUtil;

    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 50, 1000, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000));

    @Override
    public void inversion(String mineId, String dateTime, String spatialCoverage, String is, ArrayList<String> ecologicalIds,SseEmitter sseEmitter) {
        Date sqlDate = Date.valueOf(dateTime.substring(0, 10));
        logger.info("inversion:{},{},{},{},{}", mineId, dateTime, spatialCoverage, is, ecologicalIds);
        for (String ecologicalId : ecologicalIds) {
            List<DataSourcesVO> data;
            try {
                data = satelliteDataMapper.getSatelliteData(ecologicalId, sqlDate, mineId, is, spatialCoverage);
                if (data.isEmpty() || data.get(0) == null) {
                    sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_NO_DATA, mineId, dateTime, is, null, ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")));
                    return;
                }
                sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_START, mineId, dateTime, is, null, ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")));
            } catch (Exception e) {
                try {
                    sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_DATABASE_ERROR, mineId, dateTime, is, null, ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")));
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
                throw new RuntimeException(e);
            }
            logger.info("ecologicalId:{},data:{}", ecologicalId, data);
            threadPoolExecutor.execute(() -> {
                InversionResultDTO result = null;
                try {
                    result = inverseService.callEcologicalRetrievalService(ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH-mm-ss.SSS"), mineId, spatialCoverage, is, data);
                } catch (Exception e) {
                    try {
                        sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_SERVER_ERROR, mineId, dateTime, is, null, ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")));
                    } catch (IOException ignored) {
                    }
                    throw new RuntimeException(e);
                }
                InversionResultData inversionResultData = new InversionResultData();
                inversionResultData.setMineId(mineId);
                inversionResultData.setBucketName(result.getBucketName());
                inversionResultData.setFileStatus(0);
                inversionResultData.setPictureName(result.getThumbnailFileName());
                inversionResultData.setSpatialCoverage(spatialCoverage);
                inversionResultData.setEcologicalCategory(ecologicalId);
                String[] split = result.getEcologicalFileName().split("_");
                String time = split[1];
                String fixedTime = time.replaceAll("(\\d{4}-\\d{2}-\\d{2}T\\d{2})-(\\d{2})-(\\d{2}\\.\\d{3})", "$1:$2:$3");
                Instant parse = Instant.parse(fixedTime + "+08:00");
                inversionResultData.setInversionTime(parse);
                StringBuilder sb = new StringBuilder();
                for (DataSourcesVO satelliteDatum : data) {
                    sb.append(satelliteDatum.getFile_name());
                    sb.append(",");
                }
                sb.deleteCharAt(sb.length() - 1);
                inversionResultData.setDataSourceName(sb.toString());
                inversionResultData.setFileName(result.getEcologicalFileName());
                boolean insert = inversionResultDataMapper.insert(inversionResultData);
                try {
                    if (insert) {
                        sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_SUCCESS, mineId, dateTime, is, result.getEcologicalFileName(), ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")), MediaType.APPLICATION_JSON);
                        rabbitTemplate.convertAndSend(InversionDelayRabbitmqConfig.DELAY_EXCHANGE_NAME, InversionDelayRabbitmqConfig.DELAY_ROUTING_KEY, result.getEcologicalFileName());
                    } else {
                        sseEmitter.send(new InversionSseVO(sseVoEnum.INVERSION_FAIL, mineId, dateTime, is, result.getEcologicalFileName(), ecologicalId, DateUtils.dateTimeNow("yyyy-MM-dd'T'HH:mm:ss.SSS")), MediaType.APPLICATION_JSON);
                    }
                } catch (IOException ignored) {
                }
            });

        }
    }

    /**
     * 查询生态参量反演结果接口
     *
     * @param mineId
     * @param startTime
     * @param endTime
     * @param status
     * @param ecologicalId
     * @description: 根据矿区ID、日期、状态值和生态ID查询生态参量反演结果。
     */
    @Override
    public PageInfo<InversionResultVO> searchInversionResult(String mineId, Instant startTime, Instant endTime, Integer status, String ecologicalId, int pageNumber, int pageSize) {

        try {
            //分页
            PageHelper.startPage(pageNumber,pageSize);
            //获得的反演结果列表
            List<InversionResultVO> inversionResultDataList = ecologicalMapper.getInversionResultData(mineId, startTime, endTime, status, ecologicalId);
            return new PageInfo<>(inversionResultDataList);
        } catch (Exception e) {
            throw new ServiceException(e.toString());
        }

    }

    /**
     * 保存反演文件
     *
     * @param fileName
     * @description: 保存反演文件
     */
    @Override
    public boolean saveInversion(String fileName) {
        boolean result = false;
        try {
            result = ecologicalMapper.saveInversion(fileName);
        } catch (Exception e) {
            logger.error("保留反演结果失败:{}",e.toString());
            throw new RuntimeException(e);
        }
        return result;
    }

    @Override
    public ArrayList<EcologicalDataVO> selectMassiveEcologicalData(String mineId, String ecologicalCategory) {
        // 查询按照时间排列的数据
        return ecologicalMapper.selectEcologicalDataArragedByTime(mineId, ecologicalCategory);
    }

    //上传生态参量数据
    @Override
    @DataSource(DataSourceType.SLAVE)
    public void uploadData(EcologicalDataDTO ecologicalDataDTO) {
        ecologicalMapper.upload(ecologicalDataDTO);
    }

    //修改生态参量数据
    @Override
    @DataSource(DataSourceType.SLAVE)
    public void updateData(EcologicalDataDTO ecologicalDataDTO) {
        ecologicalMapper.update(ecologicalDataDTO);
    }

    //删除生态参量数据
    @Override
    @DataSource(DataSourceType.SLAVE)
    public void deleteData(Long id) {
        EcologicalData ecologicalData=ecologicalMapper.searchEcologicalDataInfoById(id);
        if(ecologicalData==null){
            throw new ServiceException(EcologicalDataException.ECOLOGICAL_DATA_NOT_FOUND);
        }
        String fileName = ecologicalData.getFileName();
        String bucketName = ecologicalData.getBucketName();
        boolean removed=minioUtil.removeFile(bucketName, fileName);
        if(!removed){
                throw new ServiceException("删除minio中对应文件失败:"+fileName);
            }

        ecologicalMapper.delete(id);
    }


}